/**
 * @author مۇختەرجان مەخمۇت (mutearjan mahmood)
 * @email yeganaaa@163.com`
 * @create date 2020-09-04 03:03:10
 * @modify date 2020-09-04 03:03:10
 * @desc [description]
*/


async function main() {
    const deleteUserImage = new DeleteFile()
    const deleteUserAvatar = new DeleteFile()
    const deleteUserData = new DeleteFile()

    const success = await TransactionContext.run(async context => {
        context.prepare([
            deleteUserImage,
            deleteUserAvatar,
            deleteUserData
        ])

        const hasDeleted = await context.run(deleteUserImage, "user.png")
        await context.run(deleteUserAvatar, "bbb.png")
        await context.run(deleteUserData, "user.data")

        return hasDeleted
    })

    console.log(success)
}

main()


interface ITransactionUnit<ARGUMENT, RETURN> {
    hasReady(): Promise<boolean>
    tryRun(argument: ARGUMENT): Promise<RETURN>
    rollback(argument: ARGUMENT): Promise<void>
    commit(argument: ARGUMENT): Promise<void>
}

class TransactionContext {
    public async prepare(units: ITransactionUnit<any, any>[]) {
        for (const unit of units) {
            await unit.hasReady()
        }
    }
    public async run<ARGUMENT, RETURN>(unit: ITransactionUnit<ARGUMENT, RETURN>, args: ARGUMENT): Promise<RETURN> {
        return await unit.tryRun(args)
    }
    public async begin(): Promise<void> {

    }
    public async commit(): Promise<void> {

    }
    public async rollback(): Promise<void> {

    }

    public static async run<RETURN>(transactionalTask: (context: TransactionContext) => Promise<RETURN>): Promise<RETURN> {
        const context = new TransactionContext()
        await context.begin()
        const result = await transactionalTask(context)
        await context.commit()
        return result
    }
}

class DeleteFile implements ITransactionUnit<string, boolean> {
    public async hasReady(): Promise<boolean> {
        return true
    }
    public async tryRun(argument: string): Promise<boolean> {
        /**Move file */
        return true
    }
    public async rollback(argument: string): Promise<void> {
        /**Move file */
    }
    public async commit(argument: string): Promise<void> {
        /**Delete file */
    }
}
